_pg = require('pg')
require('pg-parse-float')(_pg)
_pg.types.setTypeParser(20, parseInt)


Knex = require('knex')

_transaction = Knex.Client.prototype.transaction
Knex.Client.prototype.transaction = (container, config)->
    _transaction.call(
        @
        (trx)->
            Object.assign(trx,extend)
            container.apply @,arguments
        config
    )


extend = {
    rows : ->
        args = []
        for i in arguments
            args.push i
        sql = args.shift()
        r = await (@raw.call(
            @
            sql
            args
        ))
        return r.rows or []

    one: ->
        (await (@rows.apply(@,arguments)))[0]

    set:(table, id, val)->
        await @raw(
            """INSERT INTO #{table} (id,val) VALUES (?,?) ON CONFLICT (id) DO UPDATE SET val=EXCLUDED.val"""
            [
                id
                val
            ]
        )
    val:(table, id)->
        r = await @get(table, id, 'val')
        if r
            return r.val

    val_id : (table, val)->
        return (await @one(
            """INSERT INTO #{table} (val) VALUES (?) ON CONFLICT (val) DO UPDATE SET val=EXCLUDED.val RETURNING id"""
            val
        )).id

    select_val_id:(table, val)->
        o = await @one(
            """SELECT id FROM #{table} WHERE val=?""",val
        )
        if o
            return o.id

    count:(table, where)->
        (await @one("SELECT count(1) FROM #{table} WHERE #{where}")).count

    get:(table, id, column="*")->
        await @one("SELECT #{column} FROM #{table} WHERE id=?", id)

    select_id_in:(table, id_li, column="*", id="id") ->
        if not id_li.length
            return []
        li = []
        for i in id_li
            li.push(i-0)
        await @rows("SELECT #{column} FROM #{table} WHERE #{id} IN (#{li.join(',')})")


    select_id: (table, column, value)->
        sql = "SELECT id FROM #{table} WHERE #{column}=? LIMIT 1"
        r = await @raw(
            sql
            value
        )
        if r.rowCount
            return r.rows[0].id
        return 0

    insert_id: (table, column, value)->

        if value instanceof Array
            val = []
            i = value.length
            while i--
                val.push '?'
            val = val.join(',')
        else
            val = '?'

        sql = "INSERT INTO #{table} (#{column}) VALUES (#{val}) RETURNING id"
        r = await @raw(
            sql
            value
        )
        return r.rows[0].id

    upsert_id: (table, column, value)->
        # ON CONFLICT的sql会更新seq id，不要用
        sql = """with s as (select id from #{table} where "#{column}"=?),
i as (
insert into #{table} ("#{column}")
select ? where not exists (select 1 from s)
returning id
) select id from i union all select id from s"""
        r = await @raw(
            sql
            [value,value]
        )
        return r.rows[0].id
    }

module.exports = ->
    pg = Knex.apply @,arguments
    Object.assign(pg, extend)
    pg.on(
        'query-error'
        (error, obj)->
            console.error error
    )
    return pg


